//
//  KColumnHorizontalView.m
//  MengLiao
//
//  Created by xiuxin on 2022/7/15.
//  Copyright © 2022 ZHBen. All rights reserved.
//

#import "KColumnHorizontalView.h"

@interface KColumnScrollView : UIScrollView

@property (nonatomic) BOOL animating;

@end

@implementation KColumnScrollView

- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
    self.animating = animated;
    [super setContentOffset:contentOffset animated:animated];
}

@end

@interface KColumnInfo (Horizontal)

@property (nonatomic) BOOL enabled;

- (BOOL)checkAndShowInFront;

- (void)showInCell;

- (KDisplayPosition)frontPosition;

@end

@interface KColumnHorizontalView()<UIScrollViewDelegate>

@property (strong,nonatomic) UIView * scrollWrapperView;

@property (strong,nonatomic) KColumnScrollView * columnScroll;

@property (strong,nonatomic) NSMutableDictionary<NSNumber *,UIView<KColumnContentView> *> * columnViewDict;

@property (nonatomic) BOOL moving;

@property (nonatomic) CGSize viewSize;

@property (nonatomic) CGSize pageSize;

@property (nonatomic) NSInteger fromIndex;

@property (nonatomic) BOOL didLoadCurrentColumn;

@property (nonatomic) BOOL forceReload;

@end

@implementation KColumnHorizontalView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        _index = -1;
        _fromIndex = -1;
        self.viewSize = frame.size;
        self.pageSize = self.viewSize;
        self.columnViewDict = [NSMutableDictionary dictionary];
        
        self.scrollWrapperView = [[UIView alloc] initWithFrame:self.bounds];
        self.scrollWrapperView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        self.scrollWrapperView.backgroundColor = [UIColor clearColor];
        [self addSubview:self.scrollWrapperView];
        
        KColumnScrollView * scroll = [[KColumnScrollView alloc] initWithFrame:self.bounds];
        scroll.pagingEnabled = YES;
        scroll.bounces = NO;
        scroll.showsHorizontalScrollIndicator = NO;
        scroll.directionalLockEnabled = YES;
        scroll.delaysContentTouches = NO;
        scroll.canCancelContentTouches = NO;
        scroll.scrollsToTop = NO;
        scroll.delegate = self;
        scroll.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
        
        self.columnScroll = scroll;
        [self.scrollWrapperView addSubview:scroll];
    }
    return self;
}

- (void)clearColumnList:(UIView<KColumnContentView> *)columnView
{
    for (NSInteger index = 0; index < self.columnList.count; index++)
    {
        KColumnInfo * columnInfo = self.columnList[index];
        //不移除columnView 否则reload后webview重新addSubview时可能出现空白 或出现不变要的动画效果
//        if (columnInfo.scroll != columnView.scrollView)
//        {
//            [self removeViewAtIndex:index];
//        }
        [columnInfo setEnabled:NO];
    }
    _columnList = nil;
}

- (void)prepareColumnViewAtIndex:(NSInteger)index
{
    KColumnInfo * column = kObjectFromArray(self.columnList, index);
    if (column != nil)
    {
        if (column.columnView == nil)
        {
            column.columnView = [self.delegate horizontalView:self columnViewAtIndex:index];
        }
        [self setView:column.columnView atIndex:index];
    }
}

- (void)resetColumnScrollOffset:(KColumnInfo *)columnInfo displayPosition:(KDisplayPosition)displayPosition
{
    if (columnInfo.scroll != nil)
    {
        if (displayPosition == KDisplayTop)
        {
            [columnInfo setScrollOffset:CGPointZero];
        }
        else if (displayPosition == KDisplayBottom)
        {
            [columnInfo setScrollOffset:CGPointMake(0, columnInfo.scroll.contentSize.height - CGRectGetHeight(columnInfo.scroll.frame))];
        }
    }
}

- (void)resetContainerOffset:(KColumnInfo *)columnInfo fromColumn:(KColumnInfo *)fromColumn
{
    if (columnInfo.scroll != nil && columnInfo.frontPosition == KDisplayFullScreen && fromColumn.cell.window != nil)
    {
        CGFloat offsetY = CGRectGetMinY(fromColumn.cell.frame) + columnInfo.scroll.contentOffset.y - self.displayInsets.top;
        if (fabs(offsetY - self.containerView.contentOffset.y) > 0.5f)
        {
            [self.containerView setContentOffset:CGPointMake(0, offsetY) animated:NO];
        }
    }
}

- (void)showInFront:(KColumnInfo *)fromColumn thenLoadColumn:(KColumnInfo *)toColumn
{
    if (!self.forceReload)
    {
        [fromColumn checkAndShowInFront];
        [self resetContainerOffset:toColumn fromColumn:fromColumn];
    }
    [self.control loadColumnList:[NSArray arrayWithObject:toColumn]];
}

- (void)willMoveToIndex:(NSInteger)index
{
    if ([self validateIndex:index])
    {
        self.moving = YES;
        self.fromIndex = self.index;
        [self willMoveToIndex:index fromIndex:self.fromIndex];
        _index = index;
    }
}

- (void)didMoveToIndex:(NSInteger)index
{
    if ([self validateIndex:index])
    {
        _index = index;
        [self didMoveToIndex:index fromIndex:self.fromIndex];
        self.fromIndex = index;
        self.moving = NO;
    }
}

- (void)willAppear:(KColumnInfo *)columnInfo
{
    if ([columnInfo.columnView respondsToSelector:@selector(viewWillAppear)])
    {
        [columnInfo.columnView viewWillAppear];
    }
}

- (void)willDisappear:(KColumnInfo *)columnInfo
{
    if ([columnInfo.columnView respondsToSelector:@selector(viewWillDisappear)])
    {
        [columnInfo.columnView viewWillDisappear];
    }
}

- (void)willMoveToIndex:(NSInteger)toIndex fromIndex:(NSInteger)fromIndex
{
    KColumnInfo * fromColumn = self.currentColumn;
    KColumnInfo * toColumn = self.columnList[toIndex];
    
    KDisplayPosition displayPosition = fromColumn.displayPosition;

    [fromColumn setEnabled:NO];
    
    [self willDisappear:fromColumn];
    [self.delegate horizontalView:self willMoveToIndex:toIndex fromIndex:fromIndex];
    
    _currentColumn = toColumn;
    
    [self prepareColumnViewAtIndex:toIndex];
    [self willAppear:toColumn];
    
    [self resetColumnScrollOffset:toColumn displayPosition:displayPosition];
    if (roundf(self.columnScroll.contentOffset.x) == roundf(fromIndex * CGRectGetWidth(self.columnScroll.frame)))
    {
        [self showInFront:fromColumn thenLoadColumn:toColumn];
        self.didLoadCurrentColumn = YES;
    }
    else
    {
        self.didLoadCurrentColumn = NO;
    }
}

- (void)didMoveToIndex:(NSInteger)toIndex fromIndex:(NSInteger)fromIndex
{
    if (!self.moving)
    {
        [self willMoveToIndex:toIndex fromIndex:fromIndex];
    }
    if (self.currentColumn != nil
        && (!self.didLoadCurrentColumn || [self.currentColumn refreshItemSize]))
    {
        [self showInFront:kObjectFromArray(self.columnList, fromIndex) thenLoadColumn:self.currentColumn];
    }
    [self.currentColumn setEnabled:YES];
    [self.currentColumn showInCell];
    
    [self.delegate horizontalView:self didMoveToIndex:toIndex fromIndex:fromIndex];
    
    if (self.preload)
    {
        [self prepareColumnViewAtIndex:toIndex + 1];
        [self prepareColumnViewAtIndex:toIndex - 1];
    }
}

- (UIScrollView *)containerView
{
    return self.control.containerView;
}

- (void)clear
{
    [self clearColumnList:nil];
    [self setHeaderView:nil];
    [self.control loadColumnList:nil];
}

- (void)reloadWithColumnList:(NSArray<KColumnInfo *> *)columnList headerView:(UIView *)headerView toIndex:(NSInteger)toIndex
{
    NSInteger count = columnList.count;
    if (columnList.count == 0)
    {
        [self clear];
        return;
    }
    
    [self clearColumnList:columnList[toIndex].columnView];

    toIndex = MAX(MIN(toIndex, count - 1), 0);
    
    _columnList = [NSArray arrayWithArray:columnList];
    for (KColumnInfo * column in self.columnList)
    {
        column.displayInsets = self.displayInsets;
        column.control = self.control;
    }
    
//    self.headerView = headerView;
    [self configHeaderView:headerView];
    [self refreshViewSize];
    self.columnScroll.contentSize = CGSizeMake(self.viewSize.width * count, CGRectGetHeight(self.columnScroll.frame));
    
    [self _moveToIndex:toIndex animated:NO];
}

- (void)forceReload:(NSInteger)toIndex
{
    self.forceReload = YES;
    [self reload:toIndex];
    self.forceReload = NO;
}

- (void)reload:(NSInteger)toIndex
{
    if ([self.delegate respondsToSelector:@selector(numberOfColumnsInHorizontalView:)] && [self.delegate respondsToSelector:@selector(horizontalView:columnViewAtIndex:)])
    {
        NSInteger count = [self.delegate numberOfColumnsInHorizontalView:self];
        if (count == 0)
        {
            [self reloadWithColumnList:nil headerView:nil toIndex:0];
            return;
        }
        toIndex = MAX(MIN(toIndex, count - 1), 0);
        
        UIView<KColumnContentView> * currentColumnView = [self.delegate horizontalView:self columnViewAtIndex:toIndex];
        
        UIView * headerView = nil;
        if ([self.delegate respondsToSelector:@selector(headerViewForHorizontalView:)])
        {
             headerView = [self.delegate headerViewForHorizontalView:self];
        }
        
        NSMutableArray<KColumnInfo *> * columnList = [NSMutableArray arrayWithCapacity:count];
        for (NSInteger index = 0; index < count; index++)
        {
            KColumnInfo * column = [KColumnInfo new];
            column.view = self;
            if (index == toIndex)
            {
                column.columnView = currentColumnView;
            }
            [columnList addObject:column];
        }
        
        [self reloadWithColumnList:columnList headerView:headerView toIndex:toIndex];
    }
    else
    {
        [self reloadWithColumnList:self.columnList headerView:self.headerView toIndex:toIndex];
    }
}

- (void)configHeaderView:(UIView *)headerView
{
    [headerView layoutIfNeeded];
    if (_headerView != headerView)
    {
        [_headerView removeFromSuperview];
        _headerView = headerView;
        if (headerView != nil)
        {
            CGRect frame = headerView.frame;
            frame.origin = CGPointZero;
            headerView.frame = frame;
            [self insertSubview:headerView aboveSubview:self.columnScroll];
        }
    }
}

- (void)setHeaderView:(UIView *)headerView
{
    [self configHeaderView:headerView];
    [self changeHeaderHeight:headerView.frame.size.height];
}

- (void)setView:(UIView<KColumnContentView> *)view atIndex:(NSInteger)index
{
    if (self.columnViewDict[@(index)] != view)
    {
        [self removeViewAtIndex:index];
        self.columnViewDict[@(index)] = view;
        CGFloat left = self.pageSize.width * index;
        view.frame = CGRectMake(left, 0, self.pageSize.width, self.pageSize.height);
        [view layoutIfNeeded];
        [self.columnScroll addSubview:view];
    }
}

- (UIView<KColumnContentView> *)viewAtIndex:(NSInteger)index
{
    return self.columnViewDict[@(index)];
}

- (void)removeViewAtIndex:(NSInteger)index
{
    [self.columnViewDict[@(index)] removeFromSuperview];
    [self.columnViewDict removeObjectForKey:@(index)];
}

- (BOOL)validateIndex:(NSInteger)index
{
    return index >= 0 && index < self.columnList.count;
}

- (void)_moveToIndex:(NSInteger)index animated:(BOOL)animated
{
    if (animated)
    {
        [self willMoveToIndex:index];
    }
    [self.columnScroll setContentOffset:CGPointMake(self.viewSize.width * index, 0) animated:animated];
    if (!animated)
    {
        [self didMoveToIndex:index];
    }
}

- (void)resetColumnScrollOffset
{
    KDisplayPosition displayPosition = self.currentColumn.displayPosition;
    [self resetColumnScrollOffset:kObjectFromArray(self.columnList, self.index - 1) displayPosition:displayPosition];
    [self resetColumnScrollOffset:kObjectFromArray(self.columnList, self.index + 1) displayPosition:displayPosition];
}

- (void)moveToIndex:(NSInteger)index animated:(BOOL)animated
{
    if ([self validateIndex:index] && self.currentColumn != self.columnList[index])
    {
        [self _moveToIndex:index animated:animated];
    }
}

#pragma mark ScrollView Delegate Methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//    [self checkAndUpdateIndex];
    if ([self.scrollDelegate respondsToSelector:_cmd])
    {
        [self.scrollDelegate scrollViewDidScroll:scrollView];
    }
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    self.columnScroll.animating = NO;
    [self resetColumnScrollOffset];
    if ([self.scrollDelegate respondsToSelector:_cmd])
    {
        [self.scrollDelegate scrollViewWillBeginDragging:scrollView];
    }
}

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    CGFloat index = (*targetContentOffset).x / scrollView.frame.size.width;
    if (roundf(index) != (float)self.index)
    {
        [self willMoveToIndex:roundf(index)];
    }
    if ([self.scrollDelegate respondsToSelector:_cmd])
    {
        [self.scrollDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
    }
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
        [self checkAndUpdateIndex];
    }
    if ([self.scrollDelegate respondsToSelector:_cmd])
    {
        [self.scrollDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self checkAndUpdateIndex];
    if ([self.scrollDelegate respondsToSelector:_cmd])
    {
        [self.scrollDelegate scrollViewDidEndDecelerating:scrollView];
    }
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
    self.columnScroll.animating = NO;
    [self checkAndUpdateIndex];
    if ([self.scrollDelegate respondsToSelector:_cmd])
    {
        [self.scrollDelegate scrollViewDidEndScrollingAnimation:scrollView];
    }
}

- (void)checkAndUpdateIndex
{
    NSInteger index = [self offsetIndex];
    if (index >= 0)
    {
        if (index != _index)
        {
            if (self.columnScroll.animating)
            {
                _index = index;
                [self willMoveToIndex:index];
            }
            else
            {
                [self didMoveToIndex:index];
            }
        }
        else if (self.moving)
        {
            [self didMoveToIndex:index];
        }
    }
}

- (NSInteger)offsetIndex
{
    CGFloat index = self.columnScroll.contentOffset.x / self.columnScroll.bounds.size.width;
    CGFloat roundIndex = roundf(index);
    return fabs(index - roundIndex) < 0.01 ? roundIndex : -1;
}

- (void)changeHeaderHeight:(CGFloat)headerHeight
{
    if (self.headerView == nil)
    {
        headerHeight = 0;
    }
    else
    {
        CGRect headerFrame = self.headerView.frame;
        if (headerFrame.size.height != headerHeight)
        {
            headerFrame.size.height = headerHeight;
            self.headerView.frame = headerFrame;
        }
    }
    CGSize pageSize = self.viewSize;
    pageSize.height -= headerHeight;
    self.pageSize = pageSize;
    
    [self refreshSubViewFrame];
}

- (void)setFixHeader:(BOOL)fixHeader
{
    _fixHeader = fixHeader;
    self.scrollWrapperView.clipsToBounds = fixHeader;
}

- (void)containerOffsetChanged
{
    [self.currentColumn containerOffsetChanged];
    if (self.fixHeader)
    {
        CGRect frame = self.headerView.frame;
        CGFloat originY = 0;
        if (self.currentColumn.displayPosition == KDisplayTop)
        {
            if (self.headerExistOutside)
            {
                CGFloat distance = self.containerView.contentOffset.y;
                if (distance < 0)
                {
                    originY = distance;
                }
            }
        }
        else if (self.currentColumn.displayPosition == KDisplayBottom)
        {
            CGFloat distance = self.containerView.contentOffset.y + CGRectGetHeight(self.containerView.frame) - self.containerView.contentSize.height;
            if (distance > 0)
            {
                originY = distance;
            }
        }
        if (originY != frame.origin.y)
        {
            frame.origin.y = originY;
            self.headerView.frame = frame;
            
            CGFloat wrapperOriginY = self.headerView != nil ? CGRectGetMaxY(frame) : originY;
            self.scrollWrapperView.frame = CGRectMake(0, wrapperOriginY, self.pageSize.width, self.viewSize.height - wrapperOriginY);
        }
    }
}

- (void)refreshViewSize
{
    if (self.control.containerView == nil)
    {
        return;
    }
    CGSize viewSize = [self containerView].frame.size;
    viewSize.height -= (self.displayInsets.top + self.displayInsets.bottom);
    self.viewSize = viewSize;
    if (!CGSizeEqualToSize(self.frame.size, self.viewSize))
    {
        CGRect frame = self.frame;
        frame.size = self.viewSize;
        self.frame = frame;
    }
    
    CGSize pageSize = self.viewSize;
    pageSize.height = self.viewSize.height - CGRectGetHeight(self.headerView.frame);
    self.pageSize = pageSize;
    
    [self refreshSubViewFrame];
}

- (void)refreshSubViewFrame
{
    CGFloat wrapperOriginY = self.headerView != nil ? CGRectGetMaxY(self.headerView.frame) : 0;
    self.scrollWrapperView.frame = CGRectMake(0, wrapperOriginY, self.pageSize.width, self.viewSize.height - wrapperOriginY);
    
    CGRect frame = self.columnScroll.frame;
    frame.size = self.pageSize;
    frame.origin.y = CGRectGetHeight(self.scrollWrapperView.frame) - self.pageSize.height;
    self.columnScroll.frame = frame;
    
    for (UIView * columnView in self.columnViewDict.allValues)
    {
        CGRect frame1 = columnView.frame;
        frame1.size.height = self.pageSize.height;
        columnView.frame = frame1;
    }
}

- (KDisplayPosition)displayPosition
{
    return self.currentColumn.displayPosition;
}

- (UIScrollView *)scrollView
{
    return self.columnScroll;
}

@end
